/**
 * @file test_context.cpp
 * @author 心流 (iFlow CLI)
 * @brief 测试OpenCL上下文创建和管理功能
 * @version 0.1
 * @date 2025-11-26
 *
 * @copyright Copyright (c) 2025
 *
 */
#define BOOST_TEST_MODULE TestContext
#include <CL/cl.h>

#include <boost/format.hpp>
#include <boost/test/included/unit_test.hpp>
#include <boost/timer/timer.hpp>
#include <vector>

#include "test_fixture.hpp"
#include "utility.hpp"

// 测试使用clCreateContext创建上下文
BOOST_AUTO_TEST_CASE(TestCreateContext)
{
    auto platforms = GetPlatforms();
    BOOST_REQUIRE_GT(platforms.size(), 0);

    cl_platform_id platform = platforms[0];
    auto           devices  = GetDevices(platform);
    BOOST_REQUIRE_GT(devices.size(), 0);

    // 创建上下文
    cl_int     err;
    cl_context context =
        clCreateContext(nullptr, 1, &devices[0], nullptr, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(context != nullptr);

    // 验证上下文是否可以正常使用
    cl_context_info param_name = CL_CONTEXT_REFERENCE_COUNT;
    cl_uint         ref_count  = 0;
    err                        = clGetContextInfo(context,
                           CL_CONTEXT_REFERENCE_COUNT,
                           sizeof(ref_count),
                           &ref_count,
                           nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(ref_count, 0);

    // 清理
    err = clReleaseContext(context);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
}

// 测试使用clCreateContextFromType创建上下文
BOOST_AUTO_TEST_CASE(TestCreateContextFromType)
{
    // 创建指定类型的上下文
    cl_context_properties properties[] = {CL_CONTEXT_PLATFORM,
                                          0,  // 这里需要设置有效的平台ID
                                          0};

    // 先获取平台ID
    cl_uint num_platforms = 0;
    cl_int  err           = clGetPlatformIDs(0, nullptr, &num_platforms);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_REQUIRE_GT(num_platforms, 0);

    std::vector<cl_platform_id> platforms(num_platforms);
    err = clGetPlatformIDs(num_platforms, platforms.data(), nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    properties[1] = (cl_context_properties)platforms[0];

    cl_context context = clCreateContextFromType(
        properties, CL_DEVICE_TYPE_ALL, nullptr, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(context != nullptr);

    // 验证上下文
    cl_device_id device;
    err = clGetContextInfo(
        context, CL_CONTEXT_DEVICES, sizeof(device), &device, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(device != nullptr);

    // 检查设备类型
    cl_device_type device_type;
    err = clGetDeviceInfo(
        device, CL_DEVICE_TYPE, sizeof(device_type), &device_type, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK((device_type &
                 (CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU |
                  CL_DEVICE_TYPE_ACCELERATOR | CL_DEVICE_TYPE_CUSTOM)) != 0);

    // 清理
    err = clReleaseContext(context);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
}

// 测试CLWrapper中的上下文管理
BOOST_AUTO_TEST_CASE(TestCLWrapperContext)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    // 验证CLWrapper创建的上下文是否有效
    cl_context context = cl.GetContext();
    BOOST_CHECK(context != nullptr);

    // 验证上下文属性
    cl_context_info param_name = CL_CONTEXT_REFERENCE_COUNT;
    cl_uint         ref_count  = 0;
    cl_int          err        = clGetContextInfo(context,
                                  CL_CONTEXT_REFERENCE_COUNT,
                                  sizeof(ref_count),
                                  &ref_count,
                                  nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(ref_count, 0);

    // 验证上下文关联的设备
    size_t devices_size = 0;
    err                 = clGetContextInfo(
        context, CL_CONTEXT_DEVICES, 0, nullptr, &devices_size);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(devices_size, 0);

    std::vector<cl_device_id> devices(devices_size / sizeof(cl_device_id));
    err = clGetContextInfo(
        context, CL_CONTEXT_DEVICES, devices_size, devices.data(), nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(devices.size(), 0);
    BOOST_CHECK(devices[0] != nullptr);

    cl.DeInit();
}

// 测试上下文信息查询
BOOST_AUTO_TEST_CASE(TestContextInfo)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context context = cl.GetContext();
    BOOST_CHECK(context != nullptr);

    cl_device_id device = cl.GetDeviceID();
    BOOST_CHECK(device != nullptr);

    // 测试查询上下文设备信息
    size_t devices_size = 0;
    cl_int err          = clGetContextInfo(
        context, CL_CONTEXT_DEVICES, 0, nullptr, &devices_size);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(devices_size, 0);

    std::vector<cl_device_id> devices(devices_size / sizeof(cl_device_id));
    err = clGetContextInfo(
        context, CL_CONTEXT_DEVICES, devices_size, devices.data(), nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(devices.size(), 0);

    // 测试查询上下文引用计数
    cl_uint ref_count = 0;
    err               = clGetContextInfo(context,
                           CL_CONTEXT_REFERENCE_COUNT,
                           sizeof(ref_count),
                           &ref_count,
                           nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(ref_count, 0);

    // 测试查询上下文属性
    size_t properties_size = 0;
    err                    = clGetContextInfo(
        context, CL_CONTEXT_PROPERTIES, 0, nullptr, &properties_size);
    // 属性可能为空，所以不检查错误码

    if (properties_size > 0)
    {
        std::vector<cl_context_properties> properties(
            properties_size / sizeof(cl_context_properties));
        err = clGetContextInfo(context,
                               CL_CONTEXT_PROPERTIES,
                               properties_size,
                               properties.data(),
                               nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    }

    cl.DeInit();
}

// 测试多个上下文的创建和清理
BOOST_AUTO_TEST_CASE(TestMultipleContexts)
{
    cl_uint num_platforms = 0;
    cl_int  err           = clGetPlatformIDs(0, nullptr, &num_platforms);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_REQUIRE_GT(num_platforms, 0);

    std::vector<cl_platform_id> platforms(num_platforms);
    err = clGetPlatformIDs(num_platforms, platforms.data(), nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl_platform_id platform = platforms[0];

    cl_uint num_devices = 0;
    err =
        clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, nullptr, &num_devices);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_REQUIRE_GT(num_devices, 0);

    std::vector<cl_device_id> devices(num_devices);
    err = clGetDeviceIDs(
        platform, CL_DEVICE_TYPE_ALL, num_devices, devices.data(), nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    const int               num_contexts = 3;
    std::vector<cl_context> contexts(num_contexts);

    // 创建多个上下文
    for (int i = 0; i < num_contexts; i++)
    {
        contexts[i] =
            clCreateContext(nullptr, 1, &devices[0], nullptr, nullptr, &err);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
        BOOST_CHECK(contexts[i] != nullptr);
    }

    // 验证每个上下文
    for (int i = 0; i < num_contexts; i++)
    {
        cl_uint ref_count = 0;
        err               = clGetContextInfo(contexts[i],
                               CL_CONTEXT_REFERENCE_COUNT,
                               sizeof(ref_count),
                               &ref_count,
                               nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
        BOOST_CHECK_GT(ref_count, 0);
    }

    // 清理所有上下文
    for (int i = 0; i < num_contexts; i++)
    {
        err = clReleaseContext(contexts[i]);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    }
}

// 测试上下文错误处理
BOOST_AUTO_TEST_CASE(TestContextErrorHandling)
{
    cl_uint num_platforms = 0;
    cl_int  err           = clGetPlatformIDs(0, nullptr, &num_platforms);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_REQUIRE_GT(num_platforms, 0);

    std::vector<cl_platform_id> platforms(num_platforms);
    err = clGetPlatformIDs(num_platforms, platforms.data(), nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl_platform_id platform = platforms[0];

    cl_uint num_devices = 0;
    err =
        clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, nullptr, &num_devices);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_REQUIRE_GT(num_devices, 0);

    std::vector<cl_device_id> devices(num_devices);
    err = clGetDeviceIDs(
        platform, CL_DEVICE_TYPE_ALL, num_devices, devices.data(), nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 测试使用无效的设备ID创建上下文（应该失败）
    cl_device_id invalid_device = nullptr;
    cl_context   context =
        clCreateContext(nullptr, 1, &invalid_device, nullptr, nullptr, &err);
    BOOST_CHECK_NE(err, CL_SUCCESS);  // 应该失败
    BOOST_CHECK(context == nullptr);

    // 测试正常创建上下文
    context = clCreateContext(nullptr, 1, &devices[0], nullptr, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(context != nullptr);

    // 测试查询无效上下文的信息（应该失败）
    cl_uint ref_count = 0;
    err               = clGetContextInfo(nullptr,
                           CL_CONTEXT_REFERENCE_COUNT,
                           sizeof(ref_count),
                           &ref_count,
                           nullptr);
    BOOST_CHECK_NE(err, CL_SUCCESS);  // 应该失败

    // 正常清理上下文
    if (context)
    {
        err = clReleaseContext(context);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    }
}
